﻿unit uPerfEDA ;

interface

uses
  Windows,
  SysUtils,
  Classes,
  Contnrs,
  uBasic,
  uObjects,
  uPlacement,
  uViewSchematic,
  uViewPCB,
  uVisitor,
  sdXmlDocuments,
  GDIPAPI,
  ActnList ;

type
  TdmPerfEDA = class( TDataModule )
    ActionList : TActionList ;
  private
    { Private declarations }
  public
    { Public declarations }
    procedure BuildProject( aProject : TMedaProject ; aFilename : string ) ;
  end ;

  TMedaBankList = class( TObjectList )
  private
    function GetSymbol( aName : string ; aPins : integer ) : TMedaBank ;
  public
    property Symbol[ aName : string ; aPins : integer ] : TMedaBank read GetSymbol ;
  end ;

  TMedaPartList = class( TObjectList )
  private
    function GetPart( aName : string ; aRef : string ) : TMedaPart ;
  public
    property Part[ aName : string ; aRef : string ] : TMedaPart read GetPart ;
  end ;

var
  dmPerfEDA         : TdmPerfEDA ;

implementation

{$R *.dfm}

uses
  uMain ;

{ TdmPerfEDA }

procedure TdmPerfEDA.BuildProject( aProject : TMedaProject ; aFilename : string ) ;
var
  aXMLDoc           : TsdXmlDocument ;

  nEntry, nSchema,
    nPin, nPosition,
    nLogical        : TXmlNode ;

  aSymbols          : TMedaBankList ;
  aParts            : TMedaPartList ;

  aObject           : TMedaObject ;
  aModule           : TMedaModule ;
  aPart, aPartClone : TMedaPart ;
  aNet              : TMedaNet ;
  aPort             : TMedaNet ;
  aBank, aBankClone : TMedaBank ;
  aShape            : TMedaShape ;
  aPin              : TMedaPin ;
  aStack            : TMedaStack ;
  aLine             : TMedaWire ;
  aTrack            : TMedaTrack ;
  aLabel            : TMedaLabel ;
  aPower            : TMedaPower ;

  aPage             : TMedaPage ;
  aLT               : TMedaLayerType ;

  iVisible          : TMedaFlagsSet ;
  sSymbol, sLetter, sNumber : string ;

  iEntry, iSchema, iNet,
    iBank, iPosition,
    iGate, iNumGates,
    iSize, iPins    : integer ;

  iDirection        : TMedaDir ;

  iDateTime         : TDateTime ;
  iDateFormat       : TFormatSettings ;

  iTrans            : TMedaTransForm ;

  iPoint            : TGPPointF ;

  uPage, uLayer, uNode : DWORD ;

  start, stop       : single ;

  procedure DoOverlay( var iBank : TMedaBank ; iNode : TXmlNode ) ;
  var
    iPoints         : array of TGPPointF ;
    x1, y1, x2, y2  : single ;
    iPoly           : integer ;
    nPoly           : TXmlNode ;
    sAngle          : string ;
  begin
    {
    <Overlay Type="Rectangle" Solid="Yes" Width="0" Layer="0" X1="420" Y1="280" X2="400" Y2="520" />
    <Overlay Type="Line" Solid="Yes" Width="0" Layer="0" X1="500" Y1="500" X2="400" Y2="400" />
    <Overlay Type="Line" Solid="Yes" Width="0" Layer="0" X1="400" Y1="400" X2="500" Y2="300" />
    <Overlay Type="Polygon" Solid="Yes" Width="0" Layer="0">
     <Point X="490" Y="490" />
     <Point X="470" Y="440" />
     <Point X="440" Y="470" />
    </Overlay>
    <Overlay Type="Rectangle" Solid="Yes" Width="0" Layer="0" X1="220" Y1="180" X2="200" Y2="420" />
    <Overlay Type="Line" Solid="Yes" Width="0" Layer="0" X1="300" Y1="400" X2="200" Y2="300" />
    <Overlay Type="Line" Solid="Yes" Width="0" Layer="0" X1="200" Y1="300" X2="300" Y2="200" />
    <Overlay Type="Polygon" Solid="Yes" Width="0" Layer="0">
     <Point X="290" Y="390" />
     <Point X="270" Y="340" />
     <Point X="240" Y="370" />
    </Overlay>
    <Overlay Type="Line" Solid="Yes" Width="0" Layer="0" X1="300" Y1="400" X2="400" Y2="400" />
    <Overlay Type="Line" Solid="Yes" Width="0" Layer="0" X1="300" Y1="200" X2="500" Y2="200" />
    <Overlay Type="Line" Solid="Yes" Width="0" Layer="0" X1="500" Y1="300" X2="500" Y2="200" />
    <Overlay Type="Circle" Solid="Yes" Width="0" Layer="0" X1="480" Y1="180" X2="520" Y2="220" />

  <Overlay Type="Arc" Solid="Yes" Width="0" Layer="0" X1="580" Y1="350" X2="600" Y2="370" StartAngle="180.0" StopAngle="0.0" />
    }
    if LowerCase( iNode.AttributeByName( 'type' ) ) = 'rectangle' then begin
      x1 := StrToFloatDef( iNode.AttributeByName( 'x1' ), 0 ) / 10 ;
      y1 := StrToFloatDef( iNode.AttributeByName( 'y1' ), 0 ) / 10 ;
      x2 := StrToFloatDef( iNode.AttributeByName( 'x2' ), 0 ) / 10 ;
      y2 := StrToFloatDef( iNode.AttributeByName( 'y2' ), 0 ) / 10 ;
      iBank.AddRectangle( x1, y1, x2, y2 ) ;
    end
    else if LowerCase( iNode.AttributeByName( 'type' ) ) = 'line' then begin
      x1 := StrToFloatDef( iNode.AttributeByName( 'x1' ), 0 ) / 10 ;
      y1 := StrToFloatDef( iNode.AttributeByName( 'y1' ), 0 ) / 10 ;
      x2 := StrToFloatDef( iNode.AttributeByName( 'x2' ), 0 ) / 10 ;
      y2 := StrToFloatDef( iNode.AttributeByName( 'y2' ), 0 ) / 10 ;
      iBank.AddLine( x1, y1, x2, y2 ) ;
    end
    else if LowerCase( iNode.AttributeByName( 'type' ) ) = 'arc' then begin
      x1 := StrToFloatDef( iNode.AttributeByName( 'x1' ), 0 ) / 10 ;
      y1 := StrToFloatDef( iNode.AttributeByName( 'y1' ), 0 ) / 10 ;
      x2 := StrToFloatDef( iNode.AttributeByName( 'x2' ), 0 ) / 10 ;
      y2 := StrToFloatDef( iNode.AttributeByName( 'y2' ), 0 ) / 10 ;
      sAngle := iNode.AttributeByName( 'startangle' ) ;
      sAngle := StringReplace( sAngle, ',', '.', [ rfReplaceAll ] ) ;
      start := StrToFloatDef( sAngle, 0 ) ;
      sAngle := iNode.AttributeByName( 'stopangle' ) ;
      sAngle := StringReplace( sAngle, ',', '.', [ rfReplaceAll ] ) ;
      stop := StrToFloatDef( sAngle, 0 ) ;
      iBank.AddArc( x1, y1, x2, y2, start, stop ) ;
    end
    else if LowerCase( iNode.AttributeByName( 'type' ) ) = 'polygon' then try
      for iPoly := 0 to iNode.NodeCount - 1 do begin
        nPoly := iNode[ iPoly ] ;
        if LowerCase( nPoly.Name ) = 'point' then begin
          Setlength( iPoints, iPoly + 1 ) ;
          iPoints[ iPoly ].X := StrToFloatDef( nPoly.AttributeByName( 'x' ), 0 ) / 10 ;
          iPoints[ iPoly ].Y := StrToFloatDef( nPoly.AttributeByName( 'y' ), 0 ) / 10 ;
        end ;
      end ;
      iBank.AddPolygon( iPoints ) ;
    finally
      iPoints := nil ;
    end
    else if LowerCase( iNode.AttributeByName( 'type' ) ) = 'circle' then begin
      x1 := StrToFloatDef( iNode.AttributeByName( 'x1' ), 0 ) / 10 ;
      y1 := StrToFloatDef( iNode.AttributeByName( 'y1' ), 0 ) / 10 ;
      x2 := StrToFloatDef( iNode.AttributeByName( 'x2' ), 0 ) / 10 ;
      y2 := StrToFloatDef( iNode.AttributeByName( 'y2' ), 0 ) / 10 ;
      iBank.AddEllipse( x1, y1, x2, y2 ) ;
    end ;
  end ;

  function DoAngle( aNode : TXmlNode ) : integer ;
  var
    s               : string ;
  begin
    s := aNode.AttributeByName( 'angle' ) ;
    s := StringReplace( s, ',', '.', [ rfReplaceAll ] ) ;
    Result := Round( StrToFloatDef( s, 0 ) ) ;
  end ;
begin
  {
  <?xml version="1.0" encoding="UTF-8" ?>
  <SchematicProject Version="1.000" Edited="" Name="Pre Amp 2 Outputs" Author="Simon Clark" Company="Open Technologies Limited" Address="7 Tower Place, West End, Southampton, Hampshire, SO30 3DL" Telephone="02380 471583" Created="2002/11/02 18:02:22" Modified="2005/04/01 18:35:11">
   <Power Name="Vcc" Type="Circle" X="0" Y="0" Angle="180.0" Mirror="No" />
   <Power Name="Vce" Type="Circle" X="0" Y="0" Angle="0.0" Mirror="No" />
   <Power Name="+12V" Type="Arrow" X="0" Y="0" Angle="180.0" Mirror="No" />
   <Power Name="-12V" Type="Arrow" X="0" Y="0" Angle="0.0" Mirror="No" />
   <Power Name="+15V" Type="Arrow" X="0" Y="0" Angle="180.0" Mirror="No" />
   <Power Name="-15V" Type="Arrow" X="0" Y="0" Angle="0.0" Mirror="No" />
   <Power Name="0V" Type="Bar" X="0" Y="0" Angle="0.0" Mirror="No" />
   <Power Name="GND" Type="Ground" X="0" Y="0" Angle="0.0" Mirror="No" />
   <Connection Name="VOL-1-CS" Type="Passive" X="0" Y="0" Angle="0.0" Mirror="No" />
   <Net Name="VOL-1-CS" Plane="No" Visible="Yes" Type="Labelled" DefaultTrackWidth="254000" DefaultViaHoleDia="635000" DefaultViaPadDia="1016000">
    <LogicalNet ReferenceLetter="U" ReferenceNumber="1" PinOrPad="15" X="0" Y="0" Logic="Output" />
    <LogicalNet ReferenceLetter="U" ReferenceNumber="3" PinOrPad="6" X="0" Y="0" Logic="Input" />
   </Net>
   <Net Name="VOL-2-CS" Plane="No" Visible="Yes" Type="Labelled" DefaultTrackWidth="254000" DefaultViaHoleDia="635000" DefaultViaPadDia="1016000">
    <LogicalNet ReferenceLetter="U" ReferenceNumber="1" PinOrPad="1" X="0" Y="0" Logic="Output" />
    <LogicalNet ReferenceLetter="U" ReferenceNumber="6" PinOrPad="6" X="0" Y="0" Logic="Input" />
   </Net>
   <SchematicSheet Size="A4" Landscape="Yes" Title="Digital Interface" Revision="1.0" Modified="2005/04/01 18:35:07">
    <SchematicComponent Name="10u" Description="Genral Purpose 16V Minature Raial Electrolytic" ReferenceLetter="C" ReferenceNumber="1" Gate="0">
     <BodyPosition X="4100" Y="7600" Angle="0.0" Mirror="No" />
     <NamePosition X="300" Y="250" Angle="0.0" Mirror="No" />
     <ReferencePosition X="300" Y="150" Angle="0.0" Mirror="No" />
    </SchematicComponent>
    <SchematicComponent Name="10nF" Description="Multilayer Ceramic Capacitor" ReferenceLetter="C" ReferenceNumber="2" Gate="0">
     <BodyPosition X="3500" Y="7600" Angle="0.0" Mirror="No" />
     <NamePosition X="300" Y="250" Angle="0.0" Mirror="No" />
     <ReferencePosition X="300" Y="150" Angle="0.0" Mirror="No" />
    </SchematicComponent>
    <Connection Name="VOL-1-CS" Type="Output" X="5600" Y="1600" Angle="0.0" Mirror="No" />
    <Connection Name="VOL-2-CS" Type="Output" X="5600" Y="1700" Angle="0.0" Mirror="No" />
    <Power Name="0VD" Type="Bar" X="5500" Y="8200" Angle="0.0" Mirror="No" />
    <Power Name="+12VD" Type="Arrow" X="3700" Y="7500" Angle="180.0" Mirror="No" />
    <Text Name="Analogue Power" Size="Normal" X="700" Y="7800" Angle="0.0" Mirror="No" />
    <Text Name="Digital Power/Interface" Size="Normal" X="3500" Y="600" Angle="0.0" Mirror="Yes" />
    <Wire Name="+12VD" X1="3700" Y1="7700" X2="3700" Y2="7600" />
    <Wire Name="+12VD" X1="3100" Y1="7600" X2="4300" Y2="7600" />
  }
  aXMLDoc := TsdXmlDocument.Create ;
  aSymbols := TMedaBankList.Create( False ) ;
  aParts := TMedaPartList.Create( False ) ;
  with aXMLDoc do try
    DecimalSeparator := '.' ;
    LoadFromFile( aFilename ) ;
    if LowerCase( Root.Name ) = 'schematicproject' then begin
      // <SchematicProject Version="1.000" Edited="" Name="Pre Amp 2 Outputs" Author="Simon Clark" Company="Open Technologies Limited" Address="7 Tower Place, West End, Southampton, Hampshire, SO30 3DL" Telephone="02380 471583" Created="2002/11/02 18:02:22" Modified="2005/04/01 18:35:11">
      aProject.Name := Root.AttributeByName( 'name' ) ;
      aModule := aProject.NewModule ;
      aModule.Name := 'Performance EDA' ;
      for iEntry := 0 to Root.NodeCount - 1 do begin
        nEntry := Root[ iEntry ] ;
        if LowerCase( nEntry.Name ) = 'symbol' then begin
          {
           <Symbol Name="OPAMP2" Reference="U" Description="Industry Standard Dual Op Amp" Created="2000/10/15 12:20:39" Modified="2000/12/16 16:04:38" Gates="2" PGA="No">
            <NamePosition X="800" Y="300" Angle="0.0" Mirror="No" />
            <ReferencePosition X="800" Y="200" Angle="0.0" Mirror="No" />
            <Pin Name="O" Number="1" GateNumber="0" GatePin="Yes" X="800" Y="600" Angle="180.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="No" ShowNumber="Yes" Logic="Passive" />
            <Pin Name="-" Number="2" GateNumber="0" GatePin="Yes" X="300" Y="800" Angle="0.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="Yes" ShowNumber="Yes" Logic="Passive" />
            <Pin Name="+" Number="3" GateNumber="0" GatePin="Yes" X="300" Y="400" Angle="0.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="Yes" ShowNumber="Yes" Logic="Passive" />
            <Pin Name="-Vee" Number="4" GateNumber="0" GatePin="No" X="500" Y="900" Angle="90.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="No" ShowNumber="Yes" Logic="Power" />
            <Pin Name="+" Number="5" GateNumber="1" GatePin="Yes" X="300" Y="400" Angle="0.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="Yes" ShowNumber="Yes" Logic="Passive" />
            <Pin Name="-" Number="6" GateNumber="1" GatePin="Yes" X="300" Y="800" Angle="0.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="Yes" ShowNumber="Yes" Logic="Passive" />
            <Pin Name="O" Number="7" GateNumber="1" GatePin="Yes" X="800" Y="600" Angle="180.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="No" ShowNumber="Yes" Logic="Passive" />
            <Pin Name="+Vee" Number="8" GateNumber="0" GatePin="No" X="500" Y="300" Angle="270.0" Mirror="No" Style="Line" Size="1" ShowPin="Yes" ShowName="No" ShowNumber="Yes" Logic="Power" />
            <Overlay Type="Line" Solid="No" Width="0" Layer="0" X1="300" Y1="950" X2="300" Y2="250" />
            <Overlay Type="Line" Solid="No" Width="0" Layer="0" X1="300" Y1="950" X2="800" Y2="600" />
            <Overlay Type="Line" Solid="No" Width="0" Layer="0" X1="800" Y1="600" X2="300" Y2="250" />
            <Overlay Type="Line" Solid="No" Width="0" Layer="0" X1="500" Y1="900" X2="500" Y2="810" />
            <Overlay Type="Line" Solid="No" Width="0" Layer="0" X1="500" Y1="300" X2="500" Y2="390" />
           </Symbol>
          }
          {
           <Symbol Name="CAP ELEC" Reference="C" Description="Generic Symbol" Created="1997/08/06 19:13:25" Modified="2001/03/12 21:43:26" Gates="1" PGA="No">
            <NamePosition X="300" Y="250" Angle="0.0" Mirror="No" />
            <ReferencePosition X="300" Y="150" Angle="0.0" Mirror="No" />
            <Pin Name="" Number="1" GateNumber="0" GatePin="No" X="200" Y="200" Angle="270.0" Mirror="No" Style="Line" Size="0" ShowPin="Yes" ShowName="No" ShowNumber="No" Logic="Passive" />
            <Pin Name="" Number="2" GateNumber="0" GatePin="No" X="200" Y="300" Angle="90.0" Mirror="No" Style="Line" Size="0" ShowPin="Yes" ShowName="No" ShowNumber="No" Logic="Passive" />
            <Overlay Type="Rectangle" Solid="Yes" Width="0" Layer="0" X1="120" Y1="265" X2="280" Y2="300" />
            <Overlay Type="Rectangle" Solid="No" Width="0" Layer="0" X1="120" Y1="200" X2="280" Y2="235" />
           </Symbol>
          }
          {
           <Symbol Name="NPN DARL" Reference="Q" Description="" Created="1997/08/26 05:15:12" Modified="1997/08/26 05:15:12" Gates="1" PGA="No">
            <NamePosition X="525" Y="400" Angle="0.0" Mirror="No" />
            <ReferencePosition X="525" Y="300" Angle="0.0" Mirror="No" />
            <Pin Name="BASE" Number="1" GateNumber="0" GatePin="No" X="200" Y="300" Angle="0.0" Mirror="No" Style="Line" Size="0" ShowPin="Yes" ShowName="No" ShowNumber="No" Logic="Passive" />
            <Pin Name="COLLECTOR" Number="2" GateNumber="0" GatePin="No" X="500" Y="200" Angle="270.0" Mirror="No" Style="Line" Size="0" ShowPin="Yes" ShowName="No" ShowNumber="No" Logic="Passive" />
            <Pin Name="EMITTER" Number="3" GateNumber="0" GatePin="No" X="500" Y="500" Angle="90.0" Mirror="No" Style="Line" Size="0" ShowPin="Yes" ShowName="No" ShowNumber="No" Logic="Passive" />
           </Symbol>
          }
          iNumGates := StrToIntDef( nEntry.AttributeByName( 'gates' ), 0 ) ;
          for iGate := 0 to iNumGates - 1 do begin
            aBank := TMedaBank.Create ;
            aSymbols.Add( aBank ) ;
            aBank.Name := nEntry.AttributeByName( 'name' ) + '[' + IntToStr( iGate ) + ']' ;
            aBank.Designator := nEntry.AttributeByName( 'reference' ) ;
            for iBank := 0 to nEntry.NodeCount - 1 do begin
              nPin := nEntry[ iBank ] ;
              if LowerCase( nPin.Name ) = 'pin' then begin
                aPin := aBank.AddPin ;
                aPin.Name := nPin.AttributeByName( 'name' ) ;
                aPin.Designator := nPin.AttributeByName( 'number' ) ;
                iTrans.Mirror := Lowercase( nPin.AttributeByName( 'mirror' ) ) = 'yes' ;
                iTrans.Rotation := DoAngle( nPin ) ;
                iDirection := drEast ;
                case TMedaDir( iTrans.Rotation * 45 ) of
                  drEast : if not iTrans.Mirror then
                      iDirection := drWest ;
                  drNorth : iDirection := drSouth ;
                  drWest : if iTrans.Mirror then
                      iDirection := drWest ;
                  drSouth : iDirection := drNorth ;
                end ;
                iSize := StrToIntDef( nPin.AttributeByName( 'size' ), 0 ) ;
                aPin.Size := iSize + 1 ;
                iVisible := [ ] ;
                if StrToIntDef( nPin.AttributeByName( 'gatenumber' ), 0 ) = iGate then begin
                  if ( LowerCase( nPin.AttributeByName( 'showpin' ) ) = 'yes' ) then
                    iVisible := iVisible + [ vfBody ] ;
                  if LowerCase( nPin.AttributeByName( 'showname' ) ) = 'yes' then
                    iVisible := iVisible + [ vfName ] ;
                  if LowerCase( nPin.AttributeByName( 'shownumber' ) ) = 'yes' then
                    iVisible := iVisible + [ vfDesignator ] ;
                end ;
                aPin.Flags := iVisible ;
                iTrans.Position.X := Round( StrToIntDef( nPin.AttributeByName( 'x' ), 0 ) / 10 ) ;
                iTrans.Position.Y := Round( StrToIntDef( nPin.AttributeByName( 'y' ), 0 ) / 10 ) ;
                aPin.Offset := iTrans.Position ;
                aPin.Build( iDirection, pntIO ) ;
              end
              else if LowerCase( nPin.Name ) = 'overlay' then
                DoOverlay( aBank, nPin ) ;
            end ;
          end ;
        end
        else if LowerCase( nEntry.Name ) = 'part' then begin
          {
               <Part Name="10u" Reference="C" Description="Genral Purpose 16V Minature Raial Electrolytic" Symbol="CAP ELEC" Package="EEUFC1C820" PinsOrPads="2" Gates="1">
                <Details Data="" />
                <SPICEMap Name="" Columns="" />
                <SPICE Data="" />
                <Parametric Name="" Columns="Parameter&#x9;Value">
                 <Data Parameter="Tolerance" Value="20%" />
                 <Data Parameter="Working Voltage" Value="63V DC" />
                 <Data Parameter="Temperature" Value="-55°C to +105°C" />
                 <Data Parameter="Ripple @ 100kHz" Value="240mA" />
                </Parametric>
                <Supplier Name="" Columns="" />
               </Part>
          }
          aPart := TMedaPart.Create ;
          aParts.Add( aPart ) ;
          aPart.Name := nEntry.AttributeByName( 'name' ) ;
          aPart.Designator := nEntry.AttributeByName( 'reference' ) ;
          iNumGates := StrToIntDef( nEntry.AttributeByName( 'gates' ), 0 ) ;
          iPins := StrToIntDef( nEntry.AttributeByName( 'pinsorpads' ), 0 ) ;
          for iGate := 0 to iNumGates - 1 do begin
            sSymbol := nEntry.AttributeByName( 'symbol' ) + '[' + IntToStr( iGate ) + ']' ;
            aBank := aSymbols.Symbol[ sSymbol, iPins ] ;
            if assigned( aBank ) then
              aPart.AddBank.Assign( aBank ) ;
          end ;
        end
        else if LowerCase( nEntry.Name ) = 'power' then begin
          {
               <Power Name="Vcc" Type="Circle" X="0" Y="0" Angle="180.0" Mirror="No" />
          }
        end
        else if LowerCase( nEntry.Name ) = 'connection' then begin
          {
                <Connection Name="VOL-1-CS" Type="Output" X="5600" Y="1600" Angle="0.0" Mirror="No" />
          }
        end
        else if LowerCase( nEntry.Name ) = 'schematicsheet' then begin
          {
               <SchematicSheet Size="A4" Landscape="Yes" Title="Digital Interface" Revision="1.0" Modified="2005/04/01 18:35:07">
          }
          aPage := vsbSchematicViewer.AddPage(
            LowerCase( nEntry.AttributeByName( 'size' ) ),
            LowerCase( nEntry.AttributeByName( 'landscape' ) ) = 'yes'
            ) ;
          if assigned( aPage ) then begin
            sSymbol := nEntry.AttributeByName( 'title' ) ;
            aPage.Name := sSymbol ;
            sSymbol := nEntry.AttributeByName( 'revision' ) ;
            aPage.Revision := sSymbol ;
            sSymbol := nEntry.AttributeByName( 'modified' ) ;
            GetLocaleFormatSettings( 0, iDateFormat ) ;
            iDateFormat.DateSeparator := '/' ;
            iDateFormat.TimeSeparator := ':' ;
            iDateFormat.ShortDateFormat := 'yyyy/mm/dd hh:mm:ss' ;
            iDateTime := StrToDateTimeDef( sSymbol, iDateTime, iDateFormat ) ;
            aPage.Modified := iDateTime ;

            for iSchema := 0 to nEntry.NodeCount - 1 do begin
              nSchema := nEntry[ iSchema ] ;
              if LowerCase( nSchema.Name ) = 'schematiccomponent' then begin
                {
                      <SchematicComponent Name="10u" Description="Genral Purpose 16V Minature Raial Electrolytic" ReferenceLetter="C" ReferenceNumber="1" Gate="0">
                       <BodyPosition X="4100" Y="7600" Angle="0.0" Mirror="No" />
                       <NamePosition X="300" Y="250" Angle="0.0" Mirror="No" />
                       <ReferencePosition X="300" Y="150" Angle="0.0" Mirror="No" />
                      </SchematicComponent>
                }
                aPart := aParts.Part[ nSchema.AttributeByName( 'name' ), nSchema.AttributeByName( 'referenceletter' ) ] ;
                if assigned( aPart ) then begin
                  aPartClone := aModule.AddPart ;
                  aPartClone.Assign( aPart ) ;
                  aPartClone.UpdatePorts ;
                  aPartClone.Designator := nSchema.AttributeByName( 'referenceletter' ) + nSchema.AttributeByName( 'referencenumber' ) ; // + ':' + nSchema.AttributeByName( 'gate' ) ;
                  iGate := StrToIntDef( nSchema.AttributeByName( 'gate' ), 0 ) ;
                  for iPosition := 0 to nSchema.NodeCount - 1 do begin
                    nPosition := nSchema[ iPosition ] ;
                    iTrans.Mirror := Lowercase( nPosition.AttributeByName( 'mirror' ) ) = 'yes' ;
                    iTrans.Rotation := DoAngle( nPosition ) ;
                    iTrans.Position.X := Round( StrToIntDef( nPosition.AttributeByName( 'x' ), 0 ) / 10 ) ;
                    iTrans.Position.Y := Round( StrToIntDef( nPosition.AttributeByName( 'y' ), 0 ) / 10 ) ;
                    if LowerCase( nPosition.Name ) = 'bodyposition' then begin
                      // aPartClone.Place( aPage, iGate, iTrans, aBank ) ;
                      aBank := aPartClone.Banks[ iGate ] ;
                      if assigned( aBank ) then begin
                        aBank.PlaceRef := aPage.ID ;
                        aBank.Transforms[ 0 ] := iTrans ;
                        aBank.PlaceMe ;
                      end ;
                    end
                    else if assigned( aBank ) then begin
                      aPartClone.UpdatePorts( aBankClone ) ;
                      if LowerCase( nPosition.Name ) = 'nameposition' then
                        aBank.Transforms[ 1 ] := iTrans
                      else if LowerCase( nPosition.Name ) = 'referenceposition' then
                        aBank.Transforms[ 2 ] := iTrans ;
                      aBank.PlaceRef := aPage.ID ;
                      aBank.PlaceMe ;
                    end ;
                  end ;
                end ;
              end
              else if LowerCase( nSchema.Name ) = 'wire' then begin
                {
                      <Wire Name="+12VD" X1="3700" Y1="7700" X2="3700" Y2="7600" />
                }
              end ;
              {
                    <Connection Name="VOL-1-CS" Type="Output" X="5600" Y="1600" Angle="0.0" Mirror="No" />
                    <Power Name="0VD" Type="Bar" X="5500" Y="8200" Angle="0.0" Mirror="No" />
                    <Text Name="Analogue Power" Size="Normal" X="700" Y="7800" Angle="0.0" Mirror="No" />
              }
            end ;
          end ;
        end ;
      end ;
      for iEntry := 0 to Root.NodeCount - 1 do begin
        nEntry := Root[ iEntry ] ;
        if LowerCase( nEntry.Name ) = 'net' then begin
          {
               <Net Name="VOL-1-CS" Plane="No" Visible="Yes" Type="Labelled" DefaultTrackWidth="254000" DefaultViaHoleDia="635000" DefaultViaPadDia="1016000">
                <LogicalNet ReferenceLetter="U" ReferenceNumber="1" PinOrPad="15" X="0" Y="0" Logic="Output" />
                <LogicalNet ReferenceLetter="U" ReferenceNumber="3" PinOrPad="6" X="0" Y="0" Logic="Input" />
               </Net>
          }
          aNet := aModule.AddNet ;
          aNet.Name := nEntry.AttributeByName( 'name' ) ;
          for iNet := 0 to nEntry.NodeCount - 1 do begin
            nLogical := nEntry[ iNet ] ;
            sLetter := nLogical.AttributeByName( 'referenceletter' ) ;
            sNumber := nLogical.AttributeByName( 'referencenumber' ) ;
            aPort := aModule.PortByDesignator( sLetter + sNumber, nLogical.AttributeByName( 'pinorpad' ) ) ;
            aNet.ConnectPort( aPort as TMedaPort ) ;
          end ;
        end
        else if LowerCase( nEntry.Name ) = 'power' then begin
          {
               <Power Name="Vcc" Type="Circle" X="0" Y="0" Angle="180.0" Mirror="No" />
          }
          aPort := aModule.AddPort ;
          aPort.Name := nEntry.AttributeByName( 'name' ) ;
          aPort.Power := True ;
        end ;
      end ;
      for iEntry := 0 to Root.NodeCount - 1 do begin
        nEntry := Root[ iEntry ] ;
        if LowerCase( nEntry.Name ) = 'schematicsheet' then begin
          aPage := vsbSchematicViewer.PageByName( nEntry.AttributeByName( 'title' ) ) ;
          if assigned( aPage ) then begin
            for iSchema := 0 to nEntry.NodeCount - 1 do begin
              nSchema := nEntry[ iSchema ] ;
              if LowerCase( nSchema.Name ) = 'wire' then begin
                {
                      <Wire Name="+12VD" X1="3700" Y1="7700" X2="3700" Y2="7600" />
                }
                sSymbol := nSchema.AttributeByName( 'name' ) ;
                aNet := aModule.NetByName( sSymbol ) ;
                if not assigned( aNet ) then begin
                  aNet := aModule.AddNet ;
                  aNet.Name := sSymbol ;
                end ;
                aLine := aNet.AddWire ;
                iTrans.Position.X := Round( StrToIntDef( nSchema.AttributeByName( 'x1' ), 0 ) / 10 ) ;
                iTrans.Position.Y := Round( StrToIntDef( nSchema.AttributeByName( 'y1' ), 0 ) / 10 ) ;
                iPoint.X := Round( StrToIntDef( nSchema.AttributeByName( 'x2' ), 0 ) / 10 ) - iTrans.Position.X ;
                iPoint.Y := Round( StrToIntDef( nSchema.AttributeByName( 'y2' ), 0 ) / 10 ) - iTrans.Position.Y ;
                if ( iPoint.X = 0.0 ) and ( iPoint.Y = 0.0 ) then
                  aLine.AddDot( iPoint )
                else
                  aLine.AddStroke( MakePoint( 0.0, 0.0 ), iPoint ) ;
                iTrans.Rotation := 45 * integer( drEast ) ;
                iTrans.Mirror := False ;
                aLine.Transforms[ 0 ] := iTrans ;
                aLine.PlaceRef := aPage.ID ;
                aLine.PlaceMe ;
              end
              else if ( LowerCase( nSchema.Name ) = 'connection' ) then begin
                {
                      <Connection Name="VOL-1-CS" Type="Output" X="5600" Y="1600" Angle="0.0" Mirror="No" />
                }
                sSymbol := nSchema.AttributeByName( 'name' ) ;
                aNet := aModule.NetByName( sSymbol ) ;
                if not assigned( aNet ) then begin
                  aNet := aModule.AddNet ;
                  aNet.Name := sSymbol ;
                end ;
                aLabel := aNet.AddLabel ;
                sSymbol := Lowercase( nSchema.AttributeByName( 'type' ) ) ;
                //                        if sSymbol = 'passive' then
                //                           aLabel.LabelType := lbtPassive
                //                        else if sSymbol = 'input' then
                //                           aLabel.LabelType := lbtInput
                //                        else if sSymbol = 'output' then
                //                           aLabel.LabelType := lbtOutput
                //                        else if sSymbol = 'bidirectional' then
                //                           aLabel.LabelType := lbtBidir
                //                        else
                //                           aLabel.LabelType := lbtPassive ;
                iTrans.Position.X := Round( StrToIntDef( nSchema.AttributeByName( 'x' ), 0 ) / 10 ) ;
                iTrans.Position.Y := Round( StrToIntDef( nSchema.AttributeByName( 'y' ), 0 ) / 10 ) ;
                iTrans.Rotation := DoAngle( nSchema ) ;
                iTrans.Mirror := Lowercase( nSchema.AttributeByName( 'mirror' ) ) = 'yes' ;
                aLabel.Transforms[ 0 ] := iTrans ;
                aLabel.PlaceRef := aPage.ID ;
                aLabel.PlaceMe ;
              end
              else if ( LowerCase( nSchema.Name ) = 'power' ) then begin
                {
                      <Power Name="0VD" Type="Bar" X="5500" Y="8200" Angle="0.0" Mirror="No" />
                }
                sSymbol := nSchema.AttributeByName( 'name' ) ;
                aPort := aModule.PortByName( sSymbol ) ;
                if not assigned( aPort ) then begin
                  aPort := aModule.AddPort ;
                  aPort.Name := sSymbol ;
                end ;
                aPower := aPort.AddPower ;
                sSymbol := Lowercase( nSchema.AttributeByName( 'type' ) ) ;
                if sSymbol = 'bar' then
                  aPower.PowerType := pwtBar
                else if sSymbol = 'circle' then
                  aPower.PowerType := pwtCircle
                else if sSymbol = 'arrow' then
                  aPower.PowerType := pwtArrow
                else if sSymbol = 'ground' then
                  aPower.PowerType := pwtGround
                else
                  aPower.PowerType := pwtEarth ;
                iTrans.Position.X := Round( StrToIntDef( nSchema.AttributeByName( 'x' ), 0 ) / 10 ) ;
                iTrans.Position.Y := Round( StrToIntDef( nSchema.AttributeByName( 'y' ), 0 ) / 10 ) ;
                iTrans.Rotation := DoAngle( nSchema ) ;
                iTrans.Mirror := Lowercase( nSchema.AttributeByName( 'mirror' ) ) = 'yes' ;
                aPower.Transforms[ 0 ] := iTrans ;
                aPower.PlaceRef := aPage.ID ;
                aPower.PlaceMe ;
                {
                      <Text Name="Analogue Power" Size="Normal" X="700" Y="7800" Angle="0.0" Mirror="No" />
                }
              end ;
            end ;
          end ;
        end ;
      end ;
    end
    else
      ExceptionMeda.CreateFmt( 'No project found in root of file: %s', [ Root.Name ] )
  finally
    Free ;
    aSymbols.Free ;
    aParts.Free ;
    aProject.Modified ;
  end ;
end ;

{ TMedaBankList }

function TMedaBankList.GetSymbol( aName : string ; aPins : integer ) : TMedaBank ;
var
  i                 : integer ;
begin
  Result := nil ;
  for i := 0 to Count - 1 do
    if ( TMedaBank( Items[ i ] ).Name = aName ) and ( TMedaBank( Items[ i ] ).Count = aPins ) then begin
      Result := TMedaBank( Items[ i ] ) ;
      Break ;
    end ;
end ;

{ TMedaPartList }

function TMedaPartList.GetPart( aName : string ; aRef : string ) : TMedaPart ;
var
  i                 : integer ;
begin
  Result := nil ;
  for i := 0 to Count - 1 do
    if ( TMedaPart( Items[ i ] ).Name = aName ) and ( TMedaPart( Items[ i ] ).Designator = aRef ) then begin
      Result := TMedaPart( Items[ i ] ) ;
      Break ;
    end ;
end ;

end.

